﻿using Eps.Ai.Common;
using HeHe;
using InfonavaEye.model;
using Newtonsoft.Json.Linq;
using Sylan.Common.Util;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Media;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using System.Windows.Forms;
using TUCAMAPI;

namespace InfonavaEye.handler
{
    public class DeviceHandler: IPLCHandler
    {
        private UpperComputerUtil upper;

        public Action PLCInitCompleteDelegate;

        public Action moveToOriginCompleteDelegate;

        #region PLC
        /// <summary>
        /// 读取抓拍按钮状态-定时器
        /// </summary>
        private System.Timers.Timer captureTimer;

        /// <summary>
        /// 抓拍状态
        /// </summary>
        private bool captureing = false;

        /// <summary>
        /// z轴回到了圆点，通知UI
        /// </summary>
        /// <param name="imagePath"></param>
        public delegate void Z2ZeroDelegate();
        public event Z2ZeroDelegate z2ZeroDelegate;

        #endregion

        #region 相机
        TUCAM_INIT m_itApi;                 // SDK initialize environment object
        string m_filePath;                  // The file path where to save image file and video file
        string m_imageName;                 // The saved image name
        bool m_isWaiting;                   // Is waiting for the image frame
        List<TUCAM_DRAW_INIT> m_itDrawList; // The list of drawing object
        UInt64 m_drawingFramesCnt;          // The count of drawing frames
        TimeSpan m_startTime;               // The start time count
        float m_fps;                        // The current frame speed

        List<TUCAM_OPEN> m_opCamList;       // The list of opened cameras object 
        Thread m_waitingThread;             // The waiting frame thread
        int m_clientWinWidth;               // The current client window width
        int m_clientWinHeight;              // The current client window height
        TUCAM_DRAW m_drawing;               // The drawing object
        TUCAM_FRAME m_frame;                // The frame which get from SDK

        TUCAM_CAPA_ATTR m_resolutionCapa;   // The resolution capability attribute
        TUCAM_CAPA_ATTR m_binningCapa;      // The binning capability attribute
        TUCAM_CAPA_ATTR m_aeCapa;           // The auto exposure capability attribute
        TUCAM_PROP_ATTR m_gainProp;         // The gain property attribute
        TUCAM_PROP_ATTR m_aeTargetProp;     // The auto exposure time target property attribute
        TUCAM_PROP_ATTR m_exposureProp;     // The exposure time property attribute

        TUCAM_CAPA_ATTR m_autoLevelsCapa;   // The auto levels capability attribute
        TUCAM_PROP_ATTR m_leftLevelProp;    // The left level property attribute
        TUCAM_PROP_ATTR m_rightLevelProp;   // The right level property attribute
        TUCAM_PROP_ATTR m_gammaProp;        // The gamma property attribute
        TUCAM_PROP_ATTR m_contrastProp;     // The contrast property attribute
        TUCAM_PROP_ATTR m_sharpnessProp;    // The sharpness property attribute
        TUCAM_PROP_ATTR m_permeabilityProp; // The permeability property attribute

        TUCAM_CAPA_ATTR m_awbCapa;          // The auto white balance capability attribute
        TUCAM_PROP_ATTR m_redChannelProp;   // The red channel property attribute
        TUCAM_PROP_ATTR m_greenChannelProp; // The green channel property attribute
        TUCAM_PROP_ATTR m_blueChannelProp;  // The blue channel property attribute
        TUCAM_PROP_ATTR m_cctProp;          // The color temperature property attribute
        TUCAM_PROP_ATTR m_saturationProp;   // The saturation property attribute
        TUCAM_PROP_ATTR m_hueProp;          // The hue property attribute
        TUCAM_PROP_ATTR m_lightProp;        // The light property attribute

        TUCAM_CAPA_ATTR m_hdrCapa;          // The HDR capability attribute
        TUCAM_CAPA_ATTR m_verticalCapa;     // The vertical capability attribute
        TUCAM_CAPA_ATTR m_horizontalCapa;   // The horizontal capability attribute
        TUCAM_CAPA_ATTR m_monochromeCapa;   // The monochrome capability attribute

        TUCAM_TRIGGER_ATTR m_triggerAttr;   // The trigger parameter attribute

        bool m_isSupportSec;                // Is support sec
        bool m_isSupportMs;                 // Is support ms
        bool m_isSupportAeTarget;           // Is support auto exposure time target
        bool m_isSupportCCT;                // Is support color temperature
        bool m_isSupportBinng;              // Is support binning
        bool m_isSaving;                    // Is saving the image
        bool m_isRecording;                 // Is recording the video
        bool m_isRoi;                       // Is on ROI mode
        bool m_isTrigger;                   // Is trigger mode

        int m_totalFrames;                  // The saved image total frames
        int m_savedFormat;                  // The format of saved image 
        int m_savedFormatCnt;               // The count of saved image format
        int m_captureTimes;                 // The capture times
        int m_savedFramesCnt;               // The count of saved frames
        int m_savedSucceedCnt;              // The count of image succeed
        int m_indexCam;                     // The current used camera index
        private System.Windows.Forms.PictureBox drawingBox;
        public delegate void UpdateFpsInvok(string fpsStr);
        public delegate void FinishedCaptureInvok(int savedSucceedCnt);

        public delegate void CaptureImageDelegate(string imagePath);
        public event CaptureImageDelegate captureImageDelegate;

        /// <summary>
        /// 文件批次
        /// （每天每个文件批次创建一个新的文件夹：比如换了下一个钉盒，清除了数据，就需要增加这个批次）
        /// </summary>
        private int currentFileBatchNum = 1;

        private string baseDir;
        public static string CurrentBatchDir;
        private SoundPlayer soundPlayer;

        #endregion

        public DeviceHandler(System.Windows.Forms.PictureBox drawingBox)
        {
            this.drawingBox = drawingBox;
            Init();
            Start();
        }

        private void Init()
        {
            //当前目录
            IntPtr strPath = Marshal.StringToHGlobalAnsi(System.Environment.CurrentDirectory);
            baseDir = Marshal.PtrToStringAnsi(strPath);
            m_filePath = baseDir + "\\Image";

            //得到正确的currentFileBatchNum
            //（每天每个文件批次创建一个新的文件夹：比如换了下一个钉盒，清除了数据，就需要增加这个批次）
            string dir = m_filePath + "\\" + DateTime.Now.ToString("yyyy-MM-dd");
            string batchDir = dir + '\\' + currentFileBatchNum;
            if (!Directory.Exists(batchDir))
            {
                Directory.CreateDirectory(batchDir);
            }
            else
            {
                currentFileBatchNum = Directory.EnumerateFileSystemEntries(dir).Max(p =>
                {
                    var startIndex = p.LastIndexOf("\\");
                    //Console.WriteLine(p.Substring(startIndex + 1, p.Length - startIndex - 1));
                    return int.Parse(p.Substring(startIndex + 1, p.Length - startIndex - 1));
                });

                //空文件夹将继续使用，非空就创建新的
                if (Directory.GetFiles(dir + '\\' + currentFileBatchNum).Length > 0)
                {
                    currentFileBatchNum++;
                    Directory.CreateDirectory(dir + '\\' + currentFileBatchNum);
                }
            }
        }

        public void Start()
        {
            ThreadHelper.ExcuteThreadTask(() =>
            {
                StartCamera();
                initCaptureTimer();
                this.StartPLC();
            }, 50);
        }

        public void closeCamera() {
            try
            {
                if (m_opCamList != null)
                {
                    if (m_isWaiting)
                    {
                        StopWaitForFrame(m_opCamList[m_indexCam]);
                    }

                    UnInitAllOpenedCamerasDrawing();
                    this.CloseAllOpenedCameras();
                }
                this.UnInitApi();
            }
            catch (Exception e)
            {
                Console.WriteLine("关闭相机时发生异常:" + e.StackTrace);
            }

        }

        public void Close()
        {
            try
            {
                Console.WriteLine("plcHandler closed");
                isMotorOK = false;
                if (captureTimer!=null) {
                    captureTimer.Stop();
                }
                this.ClosePLC();
            }
            catch (Exception e)
            {
                Console.WriteLine("关闭串口时发生异常:" + e.StackTrace);
            }

            this.closeCamera();

            if (soundPlayer != null)
            {
                soundPlayer.Stop();
                soundPlayer.Dispose();
            }
        }

        #region 相机

        private void StartCamera()
        {
            m_opCamList = new List<TUCAM_OPEN>();
            m_itDrawList = new List<TUCAM_DRAW_INIT>();

            if (TUCAMRET.TUCAMRET_NO_CAMERA == InitApi())
            {
                MessageBox.Show("请先连接相机", "提示");
                return;
            }

            if (TUCAMRET.TUCAMRET_FAILOPEN_CAMERA == OpenAllConnectedCameras())
            {
                MessageBox.Show("打开相机失败!", "提示");
                return;
            }

            InitAllOpenedCamerasDrawing();

            // Set current selected camera
            m_indexCam = 0;
            m_isSaving = false;
            m_isRecording = false;
            m_clientWinWidth = 0;
            m_clientWinHeight = 0;

            InitImageCaptureValue();
            InitControlRange(m_opCamList[m_indexCam]);

            if (m_opCamList.Count > 0)
            {
                /*if (m_isWaiting)
                {
                    StopWaitForFrame(m_opCamList[m_indexCam]);
                }
                else
                {*/
                StartWaitForFrame(m_opCamList[m_indexCam]);
                drawingBox.Refresh();
                //}

                //EnablePanelByWaitingState(m_isWaiting);
            }
        }

        private TUCAMRET InitApi()
        {
            /* Get the current directory */
            IntPtr strPath = Marshal.StringToHGlobalAnsi(System.Environment.CurrentDirectory);

            m_filePath = Marshal.PtrToStringAnsi(strPath) + "\\Image";

            m_itApi.uiCamCount = 0;
            m_itApi.pstrConfigPath = strPath;

            TUCamAPI.TUCAM_Api_Init(ref m_itApi);

            Console.WriteLine("Connect {0} camera", m_itApi.uiCamCount);

            if (0 == m_itApi.uiCamCount)
            {
                return TUCAMRET.TUCAMRET_NO_CAMERA;
            }

            return TUCAMRET.TUCAMRET_SUCCESS;
        }

        private TUCAMRET UnInitApi()
        {
            return TUCamAPI.TUCAM_Api_Uninit();
        }

        private TUCAMRET OpenAllConnectedCameras()
        {
            // Get the camera name
            TUCAM_VALUE_INFO valueInfo;
            valueInfo.nID = (int)TUCAM_IDINFO.TUIDI_CAMERA_MODEL;
            valueInfo.nTextSize = 64;
            valueInfo.nValue = 0;
            valueInfo.pText = IntPtr.Zero;
            /* m_opCamList.Clear();
             comboBoxName.Items.Clear();*/

            for (uint i = 0; i < m_itApi.uiCamCount; ++i)
            {
                TUCAM_OPEN opCam;
                opCam.uiIdxOpen = i;
                opCam.hIdxTUCam = IntPtr.Zero;

                if (TUCAMRET.TUCAMRET_SUCCESS == TUCamAPI.TUCAM_Dev_Open(ref opCam))
                {
                    if (TUCAMRET.TUCAMRET_SUCCESS == TUCamAPI.TUCAM_Dev_GetInfo(opCam.hIdxTUCam, ref valueInfo))
                    {
                        //comboBoxName.Items.Add(Marshal.PtrToStringAnsi(valueInfo.pText) /*+ " " + labelValueSn.Text*/);
                    }

                    m_opCamList.Add(opCam);
                }
            }

            if (m_opCamList.Count > 0)
            {
                return TUCAMRET.TUCAMRET_SUCCESS;
            }

            return TUCAMRET.TUCAMRET_FAILOPEN_CAMERA;
        }

        private TUCAMRET CloseAllOpenedCameras()
        {
            for (int i = 0; i < m_opCamList.Count; ++i)
            {
                TUCamAPI.TUCAM_Dev_Close(m_opCamList[i].hIdxTUCam);
            }

            m_opCamList.Clear();

            return TUCAMRET.TUCAMRET_SUCCESS;
        }

        private void InitAllOpenedCamerasDrawing()
        {
            TUCAM_OPEN opCam;
            TUCAM_VALUE_INFO valueInfo;
            TUCAM_DRAW_INIT itDraw;
            itDraw.hWnd = drawingBox.Handle;
            itDraw.nMode = 0;

            valueInfo.nID = (int)TUCAM_IDINFO.TUIDI_CAMERA_CHANNELS;
            valueInfo.nValue = 1;
            valueInfo.nTextSize = 0;
            valueInfo.pText = IntPtr.Zero;

            m_itDrawList.Clear();

            for (int i = 0; i < m_opCamList.Count; ++i)
            {
                opCam = m_opCamList[i];

                valueInfo.nID = (int)TUCAM_IDINFO.TUIDI_CAMERA_CHANNELS;
                TUCamAPI.TUCAM_Dev_GetInfo(opCam.hIdxTUCam, ref valueInfo);
                itDraw.ucChannels = (byte)valueInfo.nValue;

                valueInfo.nID = (int)TUCAM_IDINFO.TUIDI_CURRENT_WIDTH;
                TUCamAPI.TUCAM_Dev_GetInfo(opCam.hIdxTUCam, ref valueInfo);
                itDraw.nWidth = valueInfo.nValue;

                valueInfo.nID = (int)TUCAM_IDINFO.TUIDI_CURRENT_HEIGHT;
                TUCamAPI.TUCAM_Dev_GetInfo(opCam.hIdxTUCam, ref valueInfo);
                itDraw.nHeight = valueInfo.nValue;

                TUCamAPI.TUCAM_Draw_Init(opCam.hIdxTUCam, itDraw);

                m_itDrawList.Add(itDraw);
            }
        }

        private void UnInitAllOpenedCamerasDrawing()
        {
            if (m_opCamList != null)
            {
                for (int i = 0; i < m_opCamList.Count; ++i)
                {
                    TUCamAPI.TUCAM_Draw_Uninit(m_opCamList[i].hIdxTUCam);
                }
            }

            if (m_itDrawList != null)
            {
                m_itDrawList.Clear();
            }
        }

        private void StartWaitForFrame(TUCAM_OPEN opCam)
        {
            if (m_isWaiting)
                return;

            if (m_opCamList.Count > 0)
            {
                m_isWaiting = true;
                m_waitingThread = new Thread(new ThreadStart(WaitForFrameThreadEntity));

                m_frame.pBuffer = IntPtr.Zero;
                m_frame.ucFormatGet = (byte)TUFRM_FORMATS.TUFRM_FMT_USUAl;
                m_frame.uiRsdSize = 1;

                TUCamAPI.TUCAM_Buf_Alloc(opCam.hIdxTUCam, ref m_frame);                           // Alloc buffer after set resolution or set ROI attribute                                           
                TUCamAPI.TUCAM_Cap_Start(opCam.hIdxTUCam, (uint)m_triggerAttr.nTgrMode);          // Start capture

                m_waitingThread.Start();
            }
        }

        private void StopWaitForFrame(TUCAM_OPEN opCam)
        {
            if (!m_isWaiting)
                return;

            if (m_opCamList.Count > 0)
            {
                m_isSaving = false;
                m_isWaiting = false;
                m_drawingFramesCnt = 0;
                m_startTime = new TimeSpan(DateTime.Now.Ticks);

                TUCamAPI.TUCAM_Buf_AbortWait(opCam.hIdxTUCam);
                m_waitingThread.Join();
                m_waitingThread.Abort();

                TUCamAPI.TUCAM_Cap_Stop(opCam.hIdxTUCam);                  // Stop capture   
                TUCamAPI.TUCAM_Buf_Release(opCam.hIdxTUCam);               // Release alloc buffer after stop capture and quit drawing thread
            }
        }

        private void WaitForFrameThreadEntity()
        {
            int clientWinWidth = 0;
            int clientWinHeight = 0;

            int drawingWidth = 0;
            int drawingHeight = 0;
            int drawingOffsetX = 0;
            int drawingOffsetY = 0;

            UInt64 intervalTime = 0;
            IntPtr hIdxTUCam = m_opCamList[m_indexCam].hIdxTUCam;

            while (m_isWaiting)
            {
                // Calculate the frame speed
                m_drawingFramesCnt++;
                TimeSpan stopTime = new TimeSpan(DateTime.Now.Ticks);
                intervalTime = (UInt64)m_startTime.Subtract(stopTime).Duration().TotalMilliseconds;

                if (intervalTime > 1000)
                {
                    m_fps = m_drawingFramesCnt * 1000.0f / intervalTime;

                    //UpdateFpsInvok updateFps = new UpdateFpsInvok(UpdateFps);
                    //BeginInvoke(updateFps, new object[] { m_fps.ToString("#0.0 fps") });

                    m_startTime = stopTime;
                    m_drawingFramesCnt = 0;
                }

                m_frame.ucFormatGet = (byte)TUFRM_FORMATS.TUFRM_FMT_USUAl;
                if (TUCAMRET.TUCAMRET_SUCCESS == TUCamAPI.TUCAM_Buf_WaitForFrame(hIdxTUCam, ref m_frame))
                {
                    // Change drawing area
                    if (drawingBox.Width != m_frame.usWidth || drawingBox.Height != m_frame.usHeight || m_clientWinWidth != clientWinWidth || m_clientWinHeight != clientWinHeight)
                    {
                        clientWinWidth = drawingBox.Width;
                        clientWinHeight = drawingBox.Height;

                        float scaleX = clientWinWidth * 1.0f / m_frame.usWidth;
                        float scaleY = clientWinHeight * 1.0f / m_frame.usHeight;
                        float scale = scaleX > scaleY ? scaleY : scaleX;
                        scale = (float)((int)(scale * 100) / 100.0f);

                        if (scale < 1)
                        {
                            drawingWidth = (int)(scale * m_frame.usWidth);
                            drawingHeight = (int)(scale * m_frame.usHeight);
                        }
                        else
                        {
                            drawingWidth = m_frame.usWidth;
                            drawingHeight = m_frame.usHeight;
                        }

                        drawingWidth = (drawingWidth >> 2) << 2;
                        drawingHeight = (drawingHeight >> 2) << 2;

                        drawingOffsetX = (clientWinWidth - drawingWidth) / 2;
                        drawingOffsetY = (clientWinHeight - drawingHeight) / 2;
                    }

                    // Drawing image
                    if (IntPtr.Zero != m_frame.pBuffer)
                    {
                        m_drawing.pFrame = Marshal.AllocHGlobal(Marshal.SizeOf(m_frame));
                        Marshal.StructureToPtr(m_frame, m_drawing.pFrame, true);

                        m_drawing.nDstX = drawingOffsetX;
                        m_drawing.nDstY = drawingOffsetY;
                        m_drawing.nDstWidth = drawingWidth;
                        m_drawing.nDstHeight = drawingHeight;

                        m_drawing.nSrcX = 0;
                        m_drawing.nSrcY = 0;
                        m_drawing.nSrcWidth = m_frame.usWidth;
                        m_drawing.nSrcHeight = m_frame.usHeight;
                        TUCamAPI.TUCAM_Draw_Frame(hIdxTUCam, ref m_drawing);
                    }

                    // Saving video
                    if (m_isRecording)
                    {
                        TUCamAPI.TUCAM_Rec_AppendFrame(hIdxTUCam, ref m_frame);
                    }

                    // Saving image
                    if (m_isSaving || m_isTrigger)
                    {
                        string dir = m_filePath + "\\" + DateTime.Now.ToString("yyyy-MM-dd") + "\\" + currentFileBatchNum;
                        CurrentBatchDir = dir;
                        if (!Directory.Exists(dir))
                        {
                            Directory.CreateDirectory(dir);
                        }
                        string timestamp = DateTime.Now.ToString("HHmmss");
                        //string fileName = m_filePath + "\\" + timestamp + "_" + m_imageName + "_" + m_captureTimes + "_" + m_savedFramesCnt++;
                        string fileName = dir + "\\" + timestamp + "_" + m_captureTimes;

                        bool isSucceed = false;

                        do
                        {
                            int fileFormat = m_savedFormat;
                            TUCAM_FILE_SAVE fileSave;

                            fileSave.pstrSavePath = Marshal.StringToHGlobalAnsi(fileName);

                            // struct to IntPtr
                            fileSave.pFrame = Marshal.AllocHGlobal(Marshal.SizeOf(m_frame));
                            Marshal.StructureToPtr(m_frame, fileSave.pFrame, true);

                            // Format RAW
                            if (0 != (fileFormat & (int)TUIMG_FORMATS.TUFMT_RAW))
                            {
                                fileFormat &= ~(int)TUIMG_FORMATS.TUFMT_RAW;
                            }

                            if (0 != fileFormat)
                            {
                                fileSave.nSaveFmt = fileFormat;

                                // Save other format data(TIFF/BMP/PNG/JPEG)
                                if (TUCAMRET.TUCAMRET_SUCCESS != TUCamAPI.TUCAM_File_SaveImage(hIdxTUCam, fileSave))
                                {
                                    break;
                                }
                            }

                            if (0 != (m_savedFormat & (int)TUIMG_FORMATS.TUFMT_RAW))
                            {
                                fileSave.nSaveFmt = (int)TUIMG_FORMATS.TUFMT_RAW;

                                // Get RAW data
                                m_frame.ucFormatGet = (int)TUFRM_FORMATS.TUFRM_FMT_RAW;
                                if (TUCAMRET.TUCAMRET_SUCCESS != TUCamAPI.TUCAM_Buf_CopyFrame(hIdxTUCam, ref m_frame))
                                {
                                    break;
                                }

                                // Save RAW data
                                if (TUCAMRET.TUCAMRET_SUCCESS != TUCamAPI.TUCAM_File_SaveImage(hIdxTUCam, fileSave))
                                {
                                    break;
                                }
                            }
                            /*BaiDuOcr baiDuOcr = new BaiDuOcr();
                            BaiduReturn.Text=baiDuOcr.GeneralBasicDemo(fileName+".jpg");
                            Client client=AlibabaOCR.CreateClient();
                            Stream bodySyream = AlibabaCloud.DarabonbaStream.StreamUtil.ReadFromFilePath(fileName + ".jpg");
                            AlibabaCloud.SDK.Ocr_api20210707.Models.RecognizeAdvancedRequest recognizeAdvancedRequest = new AlibabaCloud.SDK.Ocr_api20210707.Models.RecognizeAdvancedRequest
                            {
                                Body = bodySyream,
                                OutputFigure = true,
                                Row = true,
                                NeedSortPage = true,
                                NeedRotate = true,
                                OutputCharInfo = true,
                            };
                            AlibabaCloud.SDK.Ocr_api20210707.Models.RecognizeAdvancedResponse resp = client.RecognizeAdvanced(recognizeAdvancedRequest);
                            JObject jo = JObject.Parse(AlibabaCloud.TeaUtil.Common.ToJSONString(resp));
                            JObject dataJo=  JObject.Parse(jo.GetValue("Body")["Data"].ToString());
                            AlibabaCloud.TeaConsole.Client.Log(jo.GetValue("Body")["Data"].ToString());
                            //aireturn.Text = AlibabaCloud.TeaUtil.Common.ToJSONString(dataJo.GetValue("content"));
                            aireturn.Text = dataJo.GetValue("content").ToString();
                            AlibabaCloud.TeaConsole.Client.Log(AlibabaCloud.TeaUtil.Common.ToJSONString(resp));
                            TencentOCR tencentOCR = new TencentOCR();
                            TencentReturn.Text=tencentOCR.GetTencentOCR(fileName + ".jpg");*/
                            if (!string.IsNullOrEmpty(fileName))
                            {
                                string fileFullPath = fileName + ".jpg";
                                Console.WriteLine("抓拍到图片：" + fileFullPath);
                                this.captureImageDelegate.Invoke(fileFullPath);
                                this.captureing = false;
                            }

                            isSucceed = true;

                        } while (false);

                        if (isSucceed)
                        {
                            m_savedSucceedCnt++;

                            // capture finished
                            if (m_savedSucceedCnt >= m_totalFrames)
                            {
                                m_isSaving = false;

                                FinishedCaptureInvok finished = new FinishedCaptureInvok(FinishedCapture);
                                //BeginInvoke(finished, new object[] { m_savedSucceedCnt });
                                finished.Invoke(m_savedSucceedCnt);
                            }
                        }
                    }
                }
            }
        }

        public void FinishedCapture(int savedSucceedCnt)
        {
            /* buttonRecord.Enabled = true;
             buttonCapture.Enabled = true;

             buttonCapture.Text = "Capture";*/
        }

        private void InitImageCaptureValue()
        {
            int totalFrames = 1;
            /* textBoxPath.Text = m_filePath;
             textBoxImageName.Text = "TS";
             textBoxTotalFrames.Text = totalFrames.ToString();

             checkBoxTiff.Checked = true;
             checkBoxRaw.Checked = false;
             checkBoxJpg.Checked = false;
             checkBoxPng.Checked = false;
             checkBoxBmp.Checked = false;*/

            m_savedFormatCnt = 1;
            m_savedFormat = (int)(TUIMG_FORMATS.TUFMT_JPG);

            m_captureTimes = 0;
            m_savedFramesCnt = 1;
            m_savedSucceedCnt = 0;


        }

        private void InitControlRange(TUCAM_OPEN opCam)
        {
            //性能参数
            //TUCamAPI.TUCAM_Capa_SetValue(m_opCamList[m_indexCam].hIdxTUCam, (int)TUCAM_IDCAPA.TUIDC_BINNING_SUM, 1);
            //增益
            //TUCamAPI.TUCAM_Prop_SetValue(m_opCamList[m_indexCam].hIdxTUCam, (int)TUCAM_IDPROP.TUIDP_GLOBALGAIN, (double)0, 0);
            //曝光
            TUCamAPI.TUCAM_Capa_SetValue(m_opCamList[m_indexCam].hIdxTUCam, (int)TUCAM_IDCAPA.TUIDC_ATEXPOSURE, 0);//关闭自动曝光
            TUCamAPI.TUCAM_Prop_SetValue(m_opCamList[m_indexCam].hIdxTUCam, (int)TUCAM_IDPROP.TUIDP_EXPOSURETM, (double)(Config.CAMERA_EXPOSURE / 1000.0f), 0);//曝光值

            //图像水平翻转
            TUCamAPI.TUCAM_Capa_SetValue(m_opCamList[m_indexCam].hIdxTUCam, (int)TUCAM_IDCAPA.TUIDC_HORIZONTAL, 1);
            //图像垂直翻转
            TUCamAPI.TUCAM_Capa_SetValue(m_opCamList[m_indexCam].hIdxTUCam, (int)TUCAM_IDCAPA.TUIDC_VERTICAL, 1);

            if (IntPtr.Zero == opCam.hIdxTUCam)
                return;

            TUCAM_VALUE_TEXT valueText;
            valueText.nTextSize = 64;
            string textStr = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
            valueText.pText = Marshal.StringToHGlobalAnsi(textStr);

            // Get resolution range
            /*m_resolutionCapa.nValDft = 0;
            m_resolutionCapa.nValMin = 0;
            m_resolutionCapa.nValMax = 0;
            m_resolutionCapa.nValStep = 0;
            m_resolutionCapa.idCapa = (int)TUCAM_IDCAPA.TUIDC_RESOLUTION;
            if (TUCAMRET.TUCAMRET_SUCCESS == TUCamAPI.TUCAM_Capa_GetAttr(opCam.hIdxTUCam, ref m_resolutionCapa))
            {
                comboBoxRes.Items.Clear();
                int nCnt = m_resolutionCapa.nValMax - m_resolutionCapa.nValMin + 1;

                valueText.nID = (int)TUCAM_IDCAPA.TUIDC_RESOLUTION;
                for (int i = 0; i < nCnt; ++i)
                {
                    valueText.dbValue = i;
                    TUCamAPI.TUCAM_Capa_GetValueText(opCam.hIdxTUCam, ref valueText);
                    comboBoxRes.Items.Add(Marshal.PtrToStringAnsi(valueText.pText));
                }
            }*/

            // Get binning range
            /* m_binningCapa.nValDft = 0;
             m_binningCapa.nValDft = 0;
             m_binningCapa.nValMin = 0;
             m_binningCapa.nValMax = 0;
             m_binningCapa.nValStep = 0;
             m_binningCapa.idCapa = (int)TUCAM_IDCAPA.TUIDC_BINNING_SUM;
             if (TUCAMRET.TUCAMRET_SUCCESS == TUCamAPI.TUCAM_Capa_GetAttr(opCam.hIdxTUCam, ref m_binningCapa))
             {
                 m_isSupportBinng = true;

                 radioButton1x1.Enabled = true;
                 radioButton2x2.Enabled = true;
                 radioButton3x3.Enabled = true;
                 radioButton4x4.Enabled = true;
             }
             else
             {
                 m_isSupportBinng = false;

                 radioButton1x1.Enabled = false;
                 radioButton2x2.Enabled = false;
                 radioButton3x3.Enabled = false;
                 radioButton4x4.Enabled = false;
             }*/

            // Get gain range
            /* m_gainProp.dbValDft = 0;
             m_gainProp.dbValMin = 0;
             m_gainProp.dbValMax = 0;
             m_gainProp.dbValStep = 0;
             m_gainProp.idProp = (int)TUCAM_IDPROP.TUIDP_GLOBALGAIN;
             if (TUCAMRET.TUCAMRET_SUCCESS == TUCamAPI.TUCAM_Prop_GetAttr(opCam.hIdxTUCam, ref m_gainProp))
             {
                 if ((int)m_gainProp.dbValMax > 5)
                 {
                     trackBarGain.Show();

                     trackBarGain.SetRange((int)m_gainProp.dbValMin, (int)m_gainProp.dbValMax);
                 }
                 else
                 {
                     trackBarGain.Hide();
                 }
             }*/

            // Get auto exposure 
            /* m_aeCapa.nValDft = 0;
             m_aeCapa.nValMin = 0;
             m_aeCapa.nValMax = 0;
             m_aeCapa.nValStep = 0;
             m_aeCapa.idCapa = (int)TUCAM_IDCAPA.TUIDC_ATEXPOSURE;
             if (TUCAMRET.TUCAMRET_SUCCESS == TUCamAPI.TUCAM_Capa_GetAttr(opCam.hIdxTUCam, ref m_aeCapa))
             {
                 if (m_aeCapa.nValMax > 1)
                 {
                     buttonOnceAe.Show();
                     checkBoxAE.Hide();
                 }
                 else
                 {
                     buttonOnceAe.Hide();
                     checkBoxAE.Show();
                     checkBoxAE.Enabled = true;
                 }
             }
             else
             {
                 buttonOnceAe.Hide();
                 checkBoxAE.Show();
                 checkBoxAE.Enabled = false;
             }*/

            // Get auto exposure time target range
            m_aeTargetProp.dbValDft = 0;
            m_aeTargetProp.dbValMin = 0;
            m_aeTargetProp.dbValMax = 0;
            m_aeTargetProp.dbValStep = 0;
            m_aeTargetProp.idProp = (int)TUCAM_IDPROP.TUIDP_BRIGHTNESS;
            if (TUCAMRET.TUCAMRET_SUCCESS == TUCamAPI.TUCAM_Prop_GetAttr(opCam.hIdxTUCam, ref m_aeTargetProp))
            {
                /* trackBarTarget.Enabled = true;
                 labelNameTarget.Enabled = true;
                 labelValueTarget.Enabled = true;

                 m_isSupportAeTarget = true;
                 trackBarTarget.SetRange((int)m_aeTargetProp.dbValMin, (int)m_aeTargetProp.dbValMax);*/

                // MIchrome camera series must set TUIDC_ATEXPOSURE_MODE to use auto exposure time target 
                TUCamAPI.TUCAM_Capa_SetValue(opCam.hIdxTUCam, (int)TUCAM_IDCAPA.TUIDC_ATEXPOSURE_MODE, 3);
            }
            else
            {
                /*trackBarTarget.Enabled = false;
                labelNameTarget.Enabled = false;
                labelValueTarget.Enabled = false;*/

                m_isSupportAeTarget = false;
            }

            // Get exposure time range
            /* m_isSupportMs = true;
             m_isSupportSec = true;

             m_exposureProp.dbValDft = 0;
             m_exposureProp.dbValMin = 0;
             m_exposureProp.dbValMax = 0;
             m_exposureProp.dbValStep = 0;
             m_exposureProp.idProp = (int)TUCAM_IDPROP.TUIDP_EXPOSURETM;
             if (TUCAMRET.TUCAMRET_SUCCESS == TUCamAPI.TUCAM_Prop_GetAttr(opCam.hIdxTUCam, ref m_exposureProp))
             {
                 labelNameSec.Enabled = true;
                 labelNameMs.Enabled = true;
                 labelNameUs.Enabled = true;

                 numericUpDownSec.Enabled = true;
                 numericUpDownMs.Enabled = true;
                 numericUpDownUs.Enabled = true;

                 if (PID_MICHROME5PRO == m_pid || PID_MICHROME6 == m_pid)
                 {
                     m_exposureProp.dbValMin = 0.13;
                     m_exposureProp.dbValMax = 15000000;
                 }

                 uint expStep = (uint)(m_exposureProp.dbValStep * 1000 + 0.5f);

                 if ((UInt64)(m_exposureProp.dbValMax * 1000) < 1000000)
                 {
                     m_isSupportSec = false;

                     labelNameSec.Enabled = false;
                     numericUpDownSec.Enabled = false;
                 }

                 if ((UInt64)(m_exposureProp.dbValMax * 1000) < 1000)
                 {
                     m_isSupportMs = false;
                     m_isSupportSec = false;

                     labelNameSec.Enabled = false;
                     labelNameMs.Enabled = false;

                     numericUpDownSec.Enabled = false;
                     numericUpDownMs.Enabled = false;
                 }

                 numericUpDownSec.Minimum = 0;
                 numericUpDownSec.Maximum = (uint)(m_exposureProp.dbValMax / 1000);

                 numericUpDownMs.Minimum = 0;
                 numericUpDownMs.Maximum = 999;

                 numericUpDownUs.Minimum = 0;
                 numericUpDownUs.Maximum = 999;
             }*/
        }

        /// <summary>
        /// 仅采样+拉直，不进行OCR识别
        /// </summary>
        private bool isSample = false;
        /// <summary>
        /// 开始拍照（捕获）
        /// </summary>
        public void StartCapture()
        {
            m_imageName = "TS";//文件名字
            m_totalFrames = 1;//捕获帧数
            if (!Directory.Exists(m_filePath))
            {
                Directory.CreateDirectory(m_filePath, null);
            }

            Console.WriteLine("开始抓拍");
            playAudio("capture.wav");
            m_captureTimes++;
            m_savedFramesCnt = 1;
            m_savedSucceedCnt = 0;
            m_isSaving = true;
        }

        private void playAudio(string audioName)
        {
            if (soundPlayer == null)
            {
                soundPlayer = new SoundPlayer();
            }
            soundPlayer.SoundLocation = baseDir + "\\Resources\\audio\\" + audioName;
            soundPlayer.Play();
        }

        /// <summary>
        /// ListForm清除了数据，就需要增加新文件夹
        /// </summary>
        public void IncreaseCurrentFileBatchNum()
        {
            currentFileBatchNum++;
            string dir = m_filePath + "\\" + DateTime.Now.ToString("yyyy-MM-dd");
            string batchDir = dir + '\\' + currentFileBatchNum;
            if (!Directory.Exists(batchDir))
            {
                Directory.CreateDirectory(batchDir);
            }
        }

        public void SetSample(bool isSample)
        {
            this.isSample = isSample;
        }
        #endregion

        #region PLC

        public void StartPLC()
        {
            ThreadHelper.ExcuteThreadTask(() =>
            {
                StartMotor();
            }, 50);
        }

        public void ClosePLC()
        {
            try
            {
                if (upper != null)
                {
                    upper.CloseSerialPort();
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("关闭串口时发生异常:" + e.StackTrace);
            }
        }

        bool isMotorOK = false;

        private void StartMotor(Action complete = null)
        {
            if (upper != null) return;

            ThreadHelper.ExcuteThreadTask(() =>
            {
                try
                {
                    upper = new UpperComputerUtil();
                    upper.OpenSerialPort(Config.PLC_COM, 9600, 7, System.IO.Ports.StopBits.One, System.IO.Ports.Parity.Even);
                    ThreadHelper.Sleep(500);
                    if (!CheckPLC())
                    {
                        isMotorOK = false;
                        Console.WriteLine("PLC连接失败，再次尝试重连");
                        ThreadHelper.Sleep(500);
                        //再次重新连接PLC
                        StartMotor(complete);
                    }
                    else
                    {
                        isMotorOK = true;
                        Console.WriteLine("PLC已连接");
                        captureTimer.Start();

                        //设置电机速度
                        try
                        {
                            upper.SendMsgShort("D0", Config.MOTOR_X_SPEED);
                            upper.SendMsgShort("D1", Config.MOTOR_Y_SPEED);
                            upper.SendMsgShort("D2", Config.MOTOR_Z_SPEED);
                            Console.WriteLine("初始化电机速度成功");
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine("设置电机速度时发生异常,{0} {1}", ex.Message, ex.StackTrace);
                        }

                        if (this.PLCInitCompleteDelegate != null)
                        {
                            this.PLCInitCompleteDelegate.Invoke();
                        }
                    }
                }

                catch (Exception ex)
                {
                    Console.WriteLine("启动电机异常,{0} {1}", ex.Message, ex.StackTrace);
                    Logger.Write(Level.ERROR, "启动电机异常", ex);
                }
            });
        }

        private bool CheckPLC()
        {
            //获取拍照按钮状态
            JObject stopJobject = upper.ReadBoolResults("M70");

            if (stopJobject == null)
                return false;
            if (stopJobject.GetValue("Code").ToString().Equals("500"))
            {
                return false;
            }
            Console.WriteLine("PLC连接正常");
            return true;
        }

        private void initCaptureTimer()
        {
            captureTimer = new System.Timers.Timer();
            captureTimer.Interval = 20;
            //captureTimer.Enabled = true;
            captureTimer.AutoReset = false;
            captureTimer.Elapsed += new ElapsedEventHandler(Capture_Elapsed);
        }

        /// <summary>
        /// 抓拍
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Capture_Elapsed(object sender, EventArgs e)
        {
            try
            {
                if (upper == null || !isMotorOK) return;
                captureTimer.Stop();
                JObject stopJobject = upper.ReadBoolResults("M70");
                if (stopJobject == null || stopJobject.GetValue("Code").ToString().Equals("500"))
                {
                    Console.WriteLine("无法监测到拍照按钮状态," + stopJobject.GetValue("msg"));
                    return;
                }

                bool status = bool.Parse(stopJobject.GetValue("msg").ToString());
                //Console.WriteLine("Capture_Elapsed 按钮状态" + status.ToString());
                if (status)
                {
                    if (captureing)
                    {
                        //MessageBox.Show("正在抓拍，请不要重复按抓拍按钮");
                        Console.WriteLine("正在抓拍，请不要重复按抓拍按钮");
                        return;
                    }

                    captureing = true;
                    //TODO 调用相机的抓拍
                    this.StartCapture();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("抓拍，发生异常：" + ex.StackTrace);
                MessageBox.Show("抓拍发生异常，请找管理员");
            }
            finally
            {
                captureTimer.Start();
                //captureing = false;
            }
        }

        /// <summary>
        /// 开始自动抓拍
        /// </summary>
        public void startAutoCapture()
        {
            JObject stopJobject = upper.SendMsgBoolean("M110", true);
            if (stopJobject == null || stopJobject.GetValue("Code").ToString().Equals("500"))
            {
                Console.WriteLine("开启自动抓拍，发生异常：" + stopJobject.GetValue("msg").ToString());
                MessageBox.Show("开启自动抓拍发生异常，请联系管理员");
                return;
            }
        }

        /// <summary>
        /// 停止自动抓拍
        /// </summary>
        public void stopAutoCapture()
        {
            JObject stopJobject = upper.SendMsgBoolean("M199", true);
            if (stopJobject == null || stopJobject.GetValue("Code").ToString().Equals("500"))
            {
                Console.WriteLine("停止自动抓拍，发生异常：" + stopJobject.GetValue("msg").ToString());
                MessageBox.Show("停止自动抓拍发生异常，请联系管理员");
                return;
            }
        }

        /*/// <summary>
        /// 移动x轴到指定位置
        /// </summary>
        public void moveXTo(Int32 distance)
        {
            try
            {
             Console.WriteLine("设置X轴距离,进行中....期望调节到：" + distance);
            JObject D20Result = upper.SendMsgInt("D0", distance);//设置绝对距离（这个时候还不会动，要等下面M26命令执行）
                if (D20Result.GetValue("Code").ToString().Equals("500"))
                {
                    Console.WriteLine("设置X轴距离失败,D0报错：" + D20Result.GetValue("msg").ToString());
                    MessageBox.Show("设置X轴距离失败，报错" + D20Result.GetValue("msg").ToString());
                    return;
                }
                else
                {
                    JObject M26Result = upper.SendMsgBoolean("M6", true);//开始移动
                    if (M26Result.GetValue("Code").ToString().Equals("500"))
                    {
                        Console.WriteLine("移动X轴到指定距离失败,M6报错：" + M26Result.GetValue("msg").ToString());
                        MessageBox.Show("移动X轴到指定距离失败，报错" + D20Result.GetValue("msg").ToString());
                        return;
                    }
                    else
                    {
                        Console.WriteLine("移动X轴命令发送完成，等待检查移动X轴是否停稳...");
                        //TODO 如果想知道有没有停稳 ，查询D8360
                        bool stoped = false;
                        int maxTime = distance / 50;
                        int checkStopTimes = 0;
                        string checkErrorMsg = "";
                        while (!stoped)
                        {
                            if (checkStopTimes > maxTime)
                            {
                                Console.WriteLine("检查移动X轴停稳失败，超过了最大检查次数");
                                MessageBox.Show("移动X轴到指定距离失败，报错" + D20Result.GetValue("msg").ToString());
                                break;
                            }
                            try
                            {
                                Thread.Sleep(100);
                                //检查是否已经移动到目标位置
                                JObject checkResult = upper.ReadBoolResults("M6");
                                if (checkResult.GetValue("Code").ToString().Equals("0"))
                                {
                                    var attachTarget = bool.Parse(checkResult.GetValue("msg").ToString());
                                    if (!attachTarget)
                                    {
                                        stoped = true;
                                        Console.WriteLine("检查移动X轴停稳-成功!");
                                        break;
                                    }
                                    else
                                    {
                                        Console.WriteLine("...检查移动X轴停稳，还未到达目标...当前值：" + attachTarget);
                                    }
                                }
                                else
                                {
                                    checkErrorMsg = checkResult.GetValue("msg").ToString();
                                    Console.WriteLine("检查移动X轴停稳，报错：" + checkResult.GetValue("msg").ToString());
                                }
                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine("移动X轴失败,{0} {1}", ex.Message, ex.StackTrace);
                                MessageBox.Show("移动X轴失败，报错" + D20Result.GetValue("msg").ToString());
                                return;
                            }
                            finally
                            {
                                checkStopTimes++;
                            }
                        }
                    }
                }
            }catch (Exception ex)
            {
                Console.WriteLine("移动X轴失败,{0} {1}", ex.Message,ex.StackTrace);
                MessageBox.Show("移动X轴失败，报错" + ex.Message);
                return;
            }
            finally {
                focusDistanceChanged = false;
            }
        }*/

        /*/// <summary>
        /// 移动Y轴到指定位置
        /// </summary>
        public void moveYTo(Int32 distance)
        {
            try
            {
                Console.WriteLine("设置Y轴距离,进行中....期望调节到：" + distance);
                JObject D20Result = upper.SendMsgInt("D10", distance);//设置绝对距离（这个时候还不会动，要等下面M26命令执行）
                if (D20Result.GetValue("Code").ToString().Equals("500"))
                {
                    Console.WriteLine("设置Y轴距离失败,D0报错：" + D20Result.GetValue("msg").ToString());
                    MessageBox.Show("设置Y轴距离失败，报错" + D20Result.GetValue("msg").ToString());
                    return;
                }
                else
                {
                    JObject M26Result = upper.SendMsgBoolean("M16", true);//开始移动
                    if (M26Result.GetValue("Code").ToString().Equals("500"))
                    {
                        Console.WriteLine("移动Y轴到指定距离失败,M6报错：" + M26Result.GetValue("msg").ToString());
                        MessageBox.Show("移动Y轴到指定距离失败，报错" + D20Result.GetValue("msg").ToString());
                        return;
                    }
                    else
                    {
                        Console.WriteLine("移动Y轴命令发送完成，等待检查移动Y轴是否停稳...");
                        //TODO 如果想知道有没有停稳 ，查询D8360
                        bool stoped = false;
                        int maxTime = distance / 50;
                        int checkStopTimes = 0;
                        string checkErrorMsg = "";
                        while (!stoped)
                        {
                            if (checkStopTimes > maxTime)
                            {
                                Console.WriteLine("检查移动Y轴停稳失败，超过了最大检查次数");
                                MessageBox.Show("移动Y轴到指定距离失败，报错" + D20Result.GetValue("msg").ToString());
                                break;
                            }
                            try
                            {
                                Thread.Sleep(100);
                                //检查是否已经移动到目标位置
                                JObject checkResult = upper.ReadBoolResults("M16");
                                if (checkResult.GetValue("Code").ToString().Equals("0"))
                                {
                                    var attachTarget = bool.Parse(checkResult.GetValue("msg").ToString());
                                    if (!attachTarget)
                                    {
                                        stoped = true;
                                        Console.WriteLine("检查移动Y轴停稳-成功!");
                                        break;
                                    }
                                    else
                                    {
                                        Console.WriteLine("...检查移动Y轴停稳，还未到达目标...当前值：" + attachTarget);
                                    }
                                }
                                else
                                {
                                    checkErrorMsg = checkResult.GetValue("msg").ToString();
                                    Console.WriteLine("检查移动Y轴停稳，报错：" + checkResult.GetValue("msg").ToString());
                                    MessageBox.Show("检查移动Y轴停稳，报错:" + checkErrorMsg);
                                }
                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine("移动Y轴失败,{0} {1}", ex.Message, ex.StackTrace);
                                MessageBox.Show("移动Y轴失败，报错" + D20Result.GetValue("msg").ToString());
                                return;
                            }
                            finally
                            {
                                checkStopTimes++;
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("移动X轴失败,{0} {1}", ex.Message, ex.StackTrace);
                MessageBox.Show("移动X轴失败，报错" + ex.Message);
                return;
            }
            finally
            {
                focusDistanceChanged = false;
            }
        }*/


        /// <summary>
        /// 记录上一次的X位置，避免无用的指令消耗时间
        /// </summary>
        private Int32 prevX = 0;

        /// <summary>
        /// 记录上一次的Y位置，避免无用的指令消耗时间
        /// </summary>
        private Int32 prevY = 0;

        /// <summary>
        /// 记录上一次的Z位置，避免无用的指令消耗时间
        /// </summary>
        private Int32 prevZ = 0;

        /// <summary>
        /// 移动到指定位置并拍照
        /// </summary>
        public void moveToXYZandCapture(Int32 x, Int32 y, Int32 z,bool captureEnable=true)
        {
            try
            {
                bool xMoved = x != prevX;
                if (true||xMoved)
                {
                    Console.WriteLine("设置X轴距离,进行中....期望调节到：" + x);
                    JObject D20Result = upper.SendMsgInt("D9", x);//设置绝对距离（这个时候还不会动，要等下面M26命令执行）
                    if (D20Result.GetValue("Code").ToString().Equals("500"))
                    {
                        Console.WriteLine("设置X轴距离失败,D9报错：" + D20Result.GetValue("msg").ToString());
                        MessageBox.Show("设置X轴距离失败，报错" + D20Result.GetValue("msg").ToString());
                        return;
                    }
                    prevX = x;
                    Console.WriteLine("设置X轴距离,成功");
                }

                bool yMoved =  y != prevY;
                if (true || yMoved)
                {
                    Console.WriteLine("设置Y轴距离,进行中....期望调节到：" + y);
                    JObject D20Result = upper.SendMsgInt("D10", y);//设置绝对距离（这个时候还不会动，要等下面M26命令执行）
                    if (D20Result.GetValue("Code").ToString().Equals("500"))
                    {
                        Console.WriteLine("设置Y轴距离失败,D10报错：" + D20Result.GetValue("msg").ToString());
                        MessageBox.Show("设置Y轴距离失败，报错" + D20Result.GetValue("msg").ToString());
                        return;
                    }
                    prevY = y;
                    Console.WriteLine("设置Y轴距离,成功");
                }

                bool zMoved = y != prevZ;
                if (true || zMoved)
                {
                    Console.WriteLine("设置Z轴距离,进行中....期望调节到：" + z);
                    JObject D20Result = upper.SendMsgInt("D11", z);//设置绝对距离（这个时候还不会动，要等下面M26命令执行）
                    if (D20Result.GetValue("Code").ToString().Equals("500"))
                    {
                        Console.WriteLine("设置Z轴距离失败,D11报错：" + D20Result.GetValue("msg").ToString());
                        MessageBox.Show("设置Z轴距离失败，报错" + D20Result.GetValue("msg").ToString());
                        return;
                    }
                    prevZ = z;
                    Console.WriteLine("设置Z轴距离,成功");
                }

                if (true)
                {
                    JObject M26Result = upper.SendMsgBoolean(captureEnable?"M102":"M104", true);//开始移动,M102会拍照，M104不会拍照
                    if (M26Result.GetValue("Code").ToString().Equals("500"))
                    {
                        Console.WriteLine("移动xyz轴到指定距离失败,M102报错：" + M26Result.GetValue("msg").ToString());
                        MessageBox.Show("移动xyz轴到指定距离失败，报错" + M26Result.GetValue("msg").ToString());
                        return;
                    }
                    else
                    {
                        Console.WriteLine("移动XYZ轴命令发送完成，等待检查移动XYZ轴是否停稳...");
                        bool stoped = false;
                        int maxTime = Math.Max(Math.Max(Math.Max(x, y), z) / 20, 10);//默认允许检查10次
                        int checkStopTimes = 0;
                        string checkErrorMsg = "";
                        while (!stoped && !AutoCaptrueHandler.stoping)
                        {
                            if (checkStopTimes > maxTime)
                            {
                                Console.WriteLine("检查移动xyz轴停稳失败，超过了最大检查次数");
                                MessageBox.Show("移动xyz轴到指定距离失败，超过了最大检查次数");
                                break;
                            }
                            try
                            {
                                Thread.Sleep(60);
                                //检查是否已经移动到目标位置
                                JObject checkResult = upper.ReadBoolResults("M122");
                                if (checkResult.GetValue("Code").ToString().Equals("0"))
                                {
                                    var attachTarget = bool.Parse(checkResult.GetValue("msg").ToString());
                                    if (attachTarget)
                                    {
                                        stoped = true;
                                        Console.WriteLine("检查移动xyz轴停稳-成功!");
                                        break;
                                    }
                                    else
                                    {
                                        Console.WriteLine("...检查移动xyz轴停稳，还未到达目标...当前值：" + attachTarget);
                                    }
                                }
                                else
                                {
                                    checkErrorMsg = checkResult.GetValue("msg").ToString();
                                    Console.WriteLine("检查移动xyz轴停稳，报错：" + checkResult.GetValue("msg").ToString());
                                    MessageBox.Show("检查移动xyz轴停稳，报错:" + checkErrorMsg);
                                }
                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine("移动xyz轴失败,{0} {1}", ex.Message, ex.StackTrace);
                                MessageBox.Show("移动xyz轴失败，报错" + ex.Message);
                                return;
                            }
                            finally
                            {
                                checkStopTimes++;
                            }
                        }
                    }
                }
                else
                {
                    Console.WriteLine("由于xyz都没有什么变化，所有电机都没有移动");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("移动xyz轴失败,{0} {1}", ex.Message, ex.StackTrace);
                MessageBox.Show("移动xyz轴失败，报错" + ex.Message);
                return;
            }
            finally
            {
                focusDistanceChanged = false;
            }
        }

        /// <summary>
        /// 读取当前xyz坐标点位置
        /// </summary>
        /// <returns></returns>
        public int[] readCurrentXYZ()
        {
            int x = -99999;
            int y = -99999;
            int z = -99999;

            JObject xPoint = upper.ReadResultsShort("D34");
            if (xPoint == null || xPoint.GetValue("Code").ToString().Equals("500"))
            {
                string msg = "读取X轴绝对位置,发生异常：" + xPoint.GetValue("msg").ToString();
                Console.WriteLine(msg);
                throw new Exception(msg);
            }
            else
            {
                x = (int)short.Parse(xPoint.GetValue("msg").ToString());
            }

            JObject yPoint = upper.ReadResultsShort("D35");
            if (yPoint == null || yPoint.GetValue("Code").ToString().Equals("500"))
            {
                string msg = "读取Y轴绝对位置,发生异常：" + yPoint.GetValue("msg").ToString();
                Console.WriteLine(msg);
                throw new Exception(msg);
            }
            else
            {
                y = (int)short.Parse(yPoint.GetValue("msg").ToString());
            }
            JObject zPoint = upper.ReadResultsShort("D36");
            if (zPoint == null || zPoint.GetValue("Code").ToString().Equals("500"))
            {
                string msg = "读取Z轴绝对位置,发生异常：" + zPoint.GetValue("msg").ToString();
                Console.WriteLine(msg);
                throw new Exception(msg);
            }
            else
            {
                z = (int)short.Parse(zPoint.GetValue("msg").ToString());
            }

            return new int[] { x, y, z };
        }

        /// <summary>
        /// 检查是否回到了原点
        /// </summary>
        /// <returns></returns>
        public bool checkOrigin() {
            //检查是否已经移动到目标位置
            JObject checkResult = upper.ReadBoolResults("M126");
            if (checkResult.GetValue("Code").ToString().Equals("0"))
            {
                var attachTarget = bool.Parse(checkResult.GetValue("msg").ToString());
                if (attachTarget)
                {
                    backedToZero = true;
                    Console.WriteLine("检查是否回到了原点-成功!");
                }
            }
            else
            {
                Console.WriteLine("检查是否回到了原点，报错：" + checkResult.GetValue("msg").ToString());
            }
            return backedToZero;
        }

        /// <summary>
        /// 移动到机械原点
        /// </summary>
        public void moveToOrigin()
        {
            ThreadHelper.ExcuteThreadTask(() =>
            {
                JObject stopJobject = upper.SendMsgBoolean("M106", true);
                if (stopJobject == null || stopJobject.GetValue("Code").ToString().Equals("500"))
                {
                    Console.WriteLine("回到原点,发生异常：" + stopJobject.GetValue("msg").ToString());
                    MessageBox.Show("回到机械原点发生异常，请联系管理员");
                    return;
                }

                Console.WriteLine("回到机械原点命令发送完成，等待检查是否停稳...");
                bool stoped = false;
                int maxTime = 300;
                int checkStopTimes = 0;
                string checkErrorMsg = "";
                while (!stoped)
                {
                    if (checkStopTimes > maxTime)
                    {
                        Console.WriteLine("检查回到机械原点停稳失败，超过了最大检查次数");
                        //if (completeCallback != null) completeCallback(500, "检查调焦停稳失败，超过了最大检查次数,最后一次检查时报错：" + checkErrorMsg);
                        break;
                    }
                    try
                    {
                        Thread.Sleep(100);
                        //检查是否已经移动到目标位置
                        JObject checkResult = upper.ReadBoolResults("M126");
                        if (checkResult.GetValue("Code").ToString().Equals("0"))
                        {
                            var attachTarget = bool.Parse(checkResult.GetValue("msg").ToString());
                            if (attachTarget)
                            {
                                backedToZero = true;
                                stoped = true;
                                Console.WriteLine("检查回到机械原点停稳-成功!");
                                //if (completeCallback != null) completeCallback(0, "检查调焦停稳-成功");
                                break;
                            }
                            else
                            {
                                Console.WriteLine("...检查回到机械原点停稳，还未到达目标...当前值：" + attachTarget);
                            }
                        }
                        else
                        {
                            checkErrorMsg = checkResult.GetValue("msg").ToString();
                            Console.WriteLine("检查回到机械原点停稳，报错：" + checkResult.GetValue("msg").ToString());
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("回到机械原点失败,{0} {1}", ex.Message, ex.StackTrace);
                        //if (completeCallback != null) completeCallback(500, "回到机械原点发生异常：" + ex.Message);
                        return;
                    }
                    finally
                    {
                        checkStopTimes++;
                    }
                }

                if (this.moveToOriginCompleteDelegate!=null) {
                    this.moveToOriginCompleteDelegate.Invoke();
                }
            });
        }

        /// <summary>
        /// 停止移动
        /// </summary>
        public void stopMoving()
        {
            JObject stopJobject = upper.SendMsgBoolean("M199", true);
            if (stopJobject == null || stopJobject.GetValue("Code").ToString().Equals("500"))
            {
                Console.WriteLine("所有电机停止移动,发生异常：" + stopJobject.GetValue("msg").ToString());
                MessageBox.Show("所有电机停止移动发生异常，请联系管理员");
                return;
            }
            Console.WriteLine("所有电机停止移动-成功");
        }


        bool backedToZero = false;

        /// <summary>
        /// 让Z轴回原点
        /// </summary>
        public void backToZero()
        {
            //发送回到原点的指令
            Console.WriteLine("Z轴回到原点,进行中....");
            JObject commandResult = upper.SendMsgBoolean("M20", true);
            if (commandResult.GetValue("Code").ToString().Equals("500"))
            {
                MessageBox.Show("让Z轴回到原点失败");
                Console.WriteLine("让Z轴回到原点失败，报错：" + commandResult.GetValue("msg").ToString());
            }
            else
            {
                while (!backedToZero)
                {
                    Thread.Sleep(500);
                    //检查是否已经回到了原点
                    JObject checkResult = upper.ReadBoolResults("M24");
                    if (checkResult.GetValue("Code").ToString().Equals("0"))
                    {
                        if (Boolean.Parse(checkResult.GetValue("msg").ToString()))
                        {
                            backedToZero = true;
                            Console.WriteLine("检查Z轴回到原点-成功!");
                            if (z2ZeroDelegate != null)
                            {
                                z2ZeroDelegate.Invoke();
                            }
                        }
                        else
                        {
                            Console.WriteLine("...检查到Z轴还未回到原点...");
                        }
                    }
                    else
                    {
                        Console.WriteLine("检查Z轴回到原点失败，报错：" + checkResult.GetValue("msg").ToString());
                    }
                }
            }
        }

        bool focusDistanceChanged = false;
        /// <summary>
        /// 调节焦距
        /// （调节Z轴的位置）
        /// </summary>
        public void ChangeFocusDistance(int distance, Action<int, string> completeCallback)
        {
            Console.WriteLine("调节焦距目标：" + distance);
           /* if (!backedToZero)
            {
                Console.WriteLine("Z轴还未回到原点，无法继续调节");
                if (completeCallback != null) completeCallback(501, "Z轴还未回到原点，无法继续调节");
                return;
            }*/

            if (distance > 10000)
            {
                Console.WriteLine("调节焦距失败，距离不能大于10000");
                if (completeCallback != null) completeCallback(502, "调节焦距失败，距离不能大于10000");
                return;
            }

            if (focusDistanceChanged)
            {
                Console.WriteLine("调节焦距失败，前一个调节任务正在执行中");
                if (completeCallback != null) completeCallback(503, "调节焦距失败，前一个调节任务正在执行中");
                return;
            }

            try
            {
                focusDistanceChanged = true;
                Console.WriteLine("调节焦距,进行中....期望调节到：" + distance);
                JObject D20Result = upper.SendMsgInt("D8", distance);//设置绝对距离（这个时候还不会动，要等下面M26命令执行）
                if (D20Result.GetValue("Code").ToString().Equals("500"))
                {
                    Console.WriteLine("调节焦距失败,D20报错：" + D20Result.GetValue("msg").ToString());
                    if (completeCallback != null) completeCallback(500, "调节焦距时设置距离报错：" + D20Result.GetValue("msg").ToString());
                    return;
                }
                else
                {
                    JObject M26Result = upper.SendMsgBoolean("M8", true);//开始移动
                    if (M26Result.GetValue("Code").ToString().Equals("500"))
                    {
                        Console.WriteLine("调节焦距失败,M26报错：" + M26Result.GetValue("msg").ToString());
                        if (completeCallback != null) completeCallback(500, "调节焦距时报错：" + M26Result.GetValue("msg").ToString());
                        return;
                    }
                    else
                    {
                        Console.WriteLine("调节焦距命令发送完成，等待检查调焦是否停稳...");
                        //TODO 如果想知道有没有停稳 ，查询D8360
                        bool stoped = false;
                        int maxTime = distance/100;
                        int checkStopTimes = 0;
                        string checkErrorMsg = "";
                        while (!stoped)
                        {
                            if (checkStopTimes > maxTime)
                            {
                                Console.WriteLine("检查调焦停稳失败，超过了最大检查次数");
                                if (completeCallback != null) completeCallback(500, "检查调焦停稳失败，超过了最大检查次数,最后一次检查时报错：" + checkErrorMsg);
                                break;
                            }
                            try
                            {
                                Thread.Sleep(100);
                                //检查是否已经移动到目标位置
                                JObject checkResult = upper.ReadBoolResults("M25");
                                if (checkResult.GetValue("Code").ToString().Equals("0"))
                                {
                                    var attachTarget = bool.Parse(checkResult.GetValue("msg").ToString());
                                    if (attachTarget)
                                    {
                                        stoped = true;
                                        Console.WriteLine("检查调焦停稳-成功!");
                                        upper.SendMsgBoolean("M25", false);
                                        if (completeCallback != null) completeCallback(0, "检查调焦停稳-成功");
                                        break;
                                    }
                                    else
                                    {
                                        Console.WriteLine("...检查调焦停稳，还未到达目标...当前值：" + attachTarget);
                                    }
                                }
                                else
                                {
                                    checkErrorMsg = checkResult.GetValue("msg").ToString();
                                    Console.WriteLine("检查调焦停稳，报错：" + checkResult.GetValue("msg").ToString());
                                }
                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine("调节焦距失败,{0} {1}", ex.Message, ex.StackTrace);
                                if (completeCallback != null) completeCallback(500, "调节焦距发生异常：" + ex.Message);
                                return;
                            }
                            finally
                            {
                                checkStopTimes++;
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("调节焦距失败,{0} {1}", ex.Message, ex.StackTrace);
                if (completeCallback != null) completeCallback(500, "调节焦距发生异常：" + ex.Message);
                return;
            }
            finally
            {
                focusDistanceChanged = false;
            }

            if (completeCallback != null) completeCallback(0, "调节成功!");
        }

        public void SendCommond(string action, object param)
        {
            JObject result = null;
            if (upper == null)
            {
                MessageBox.Show("还未成功初始化硬件连接");
                return;
            }
            switch (action.ToUpper())
            {
                //焦距调节
                //case "FOCUS_DISTANCE":
                //ChangeFocusDistance(int.Parse(param.ToString()),null);
                // break;
                //亮度调节
                case "BRIGHTNESS":
                    result = upper.SendMsg("Xxxx", param.ToString());
                    if (result == null || result.GetValue("Code").ToString().Equals("500"))
                    {
                        Console.WriteLine("亮度调节失败," + result.GetValue("msg"));
                        MessageBox.Show("亮度调节失败," + result.GetValue("msg"));
                        return;
                    }
                    else
                    {
                        //记录到配置文件中
                        Config.LAMP_BRIGHTNESS = (int)param;
                        Config.INI.WriteValue("device", "LAMP_BRIGHTNESS", param.ToString());//修改配置文件
                    }
                    break;
                default:

                    break;
            }

        }

        #endregion
    }
}